
#include "sdl.h"

#include <SDL/SDL.h>
#include <v8.h>

#include "sdl-color-conv.h"

using namespace v8;

namespace js {
namespace bindings {
namespace sdl {

/**
 * SDL Application
 */
class SdlApp {
public:
    SdlApp()
        : m_signature("jsdl App")
        , m_screen(0)
        , m_background_color(0x00000000)
    {}

    int run() {
        int                 result = 0;
        const int           screenW = 640;
        const int           screenH = 480;
        const int           screenBpp = 32;
        const int           flags = SDL_HWSURFACE;//SDL_SWSURFACE;

        result = SDL_Init(SDL_INIT_VIDEO  | SDL_INIT_TIMER);

        if (!result)
        {
            m_screen = SDL_SetVideoMode(screenW, screenH, screenBpp, flags);
            if (!m_screen)
            {
                const char * sdl_err = SDL_GetError();
                fprintf(stderr, "Can't set video mode: %s\n", sdl_err);
                result = -1;
            }
        }

        if (!result) { SDL_WM_SetCaption("jsdl Application", "jsdl"); }

        //if(!result) {result = load_res(app); }
        if (!result) { result = init_msg_loop(); }
        //if (!result) {unload_res(app);}

        SDL_Quit();

        return result;
    }

    SdlColor background_color() const {
        return m_background_color;
    }

    void set_background_color(SdlColor color) {
        m_background_color = color;
    }

private:
    const char * m_signature;
    SDL_Surface * m_screen;
    SdlColor m_background_color;

    int init_msg_loop() {
        int                 result = 0;
        SDL_Event           e;
        bool                redraw_omitted = false; // this is to not to omit redraw even on high load

        // app loop
        for (;;)
        {
            if ((0 != SDL_PollEvent(&e)) && !redraw_omitted)
            {
                redraw_omitted = true;
                switch (e.type)
                {
                case SDL_KEYDOWN:
                    // escape quits application
                    if (e.key.keysym.sym == SDLK_ESCAPE)
                    {
                        goto EndLoop;
                    }

                    //handle_kbd(app, sdlEvent.key.keysym.sym);

                    break;

                case SDL_QUIT:
                    goto EndLoop;
                    break;
                }
            }
            else
            {
                redraw_omitted = false;

                // do logic and draw
                do_logic();
                draw_scene();
            }
        }

    EndLoop:
        SDL_Quit();

        return result;
    }

    void do_logic() {
        ;
    }


    void draw_scene() {
        /* fill bg */
        {
            SDL_Rect fullRect;
            fullRect.x = fullRect.y = 0;
            fullRect.w = m_screen->w;
            fullRect.h = m_screen->h;
            SDL_FillRect(m_screen, &fullRect, m_background_color);
        }

        /* test square */
        {
            SDL_Rect fullRect;
            fullRect.x = fullRect.y = 10;
            fullRect.w = 320;
            fullRect.h = 240;
            SDL_FillRect(m_screen, &fullRect, 0xFFFF00FF);
        }

        /* update screen */
        SDL_UpdateRect(m_screen, 0, 0, 0, 0);
    }
};

struct SdlAppBindings {
    static Handle<Value> GetBackgroundColor(Local<String> property, const AccessorInfo& info) {
        SdlApp * app = static_cast<SdlApp *>(info.Holder()->GetPointerFromInternalField(0));

        ::Uint32 color = app->background_color();

        Handle<Array> result = Array::New(4);

        // set all the corresponding color values
        result->Set(0, Integer::New((color >> 16) & 0xff));
        result->Set(1, Integer::New((color >> 8) & 0xff));
        result->Set(2, Integer::New((color >> 0) & 0xff));
        result->Set(3, Integer::New(color >> 24));

        return result;
    }

    static void SetBackgroundColor(Local<String> property, Local<Value> value, const AccessorInfo& info) {
        SdlApp * app = static_cast<SdlApp *>(info.Holder()->GetPointerFromInternalField(0));

        SdlColor color;

        if (value->IsArray()) {
            Local<Array> array = Array::Cast(*value);
            SdlColor r = array->Get(0)->Uint32Value();
            SdlColor g = array->Get(1)->Uint32Value();
            SdlColor b = array->Get(2)->Uint32Value();
            SdlColor a = array->Get(3)->Uint32Value();

            color = b + (g << 8) + (r << 16) + (a << 24);
        }
        else if (value->IsString()) {
            String::AsciiValue str_value(value);
            color = color_from_string(*str_value);
        }
        else {
            color = 0;
        }

        app->set_background_color(color);
    }
};

void add_globals(Handle<ObjectTemplate>& globals, SdlApp * app) {
    Handle<ObjectTemplate> app_template = ObjectTemplate::New();
    app_template->SetInternalFieldCount(1);

    app_template->SetAccessor(String::New("backgroundColor"),
                              SdlAppBindings::GetBackgroundColor,
                              SdlAppBindings::SetBackgroundColor);

    // wrapper around app
    Local<Object> wrapped_app = app_template->NewInstance();
    wrapped_app->SetPointerInInternalField(0, app);

    globals->Set("sdlApp", wrapped_app);
}

SdlApp * create_sdl_app() {
    SdlApp * app = new SdlApp();
    return app;
}

int run_sdl_app(SdlApp * app) {
    return app->run();
}

void free_sdl_app(SdlApp * app) {
    delete app;
}

} // namespace sdl
} // namespace bindings
} // namespace js
